<?php
/**
 * usersettingsrecaptcha.php
 * Refactored User Settings Action (login/registration) with ReCaptcha
 *
 * References
 *      http://klenwell.com/is/WikkaBaseActionClass
 *
 * @package     Action
 * @author      Tom Atwell <klenwell@gmail.com>
 * @copyright   Copyright 2010, Tom Atwell <klenwell@gmail.com>
 * @license     http://www.gnu.org/copyleft/gpl.html GNU General Public License
 *
 * @uses        Wakka::GetUser()
 * @uses        TBA
 *
 * @input       TBA
 * @output      TBA
 */

require_once 'libs/action.class.php';
require_once 'libs/userregistration.class.php';

class UserLoginAction extends WikkaAction {

    var $version = '0.4.2';

    # parameter defaults
    # N/A

    # defaults
    var $action                             = '';
    var $password_min_length                = 5;
    var $valid_email_pattern                = '/^.+?\@.+?\..+$/';
    var $revision_limit_min                 = 0;    # 0 means none
    var $revision_limit_max                 = 20;
    var $recentchanges_limit_min            = 0;
    var $recentchanges_limit_max            = 50;
    var $quick_links                        = '<!-- see setup method -->';

    # messages
    var $message_logout                     = 'You have been logged out.';
    var $message_registered                 = 'You have successfully registered!';
    var $message_user_updated               = 'User settings stored!';
    var $message_password_changed           = 'Password successfully changed!';

    # error strings
    var $error_username_empty               = 'Please fill in your user name.';
    var $error_pass1_empty                  = 'Please fill in a password.';
    var $error_user_not_found               = 'User name not found';
    var $error_user_suspended               = '<!-- see setup method -->';
    var $error_wrong_password               = 'Incorrect password.';
    var $error_email_address_required       = 'Please specify an email address.';
    var $error_invalid_email_address        = 'That email address is not valid.';
    var $error_invalid_revision_limit       = 'Keep page revisions limit between %d and %d';
    var $error_invalid_change_limit         = 'Keep recently changed pages limit between %d and %d';
    var $error_invalid_registration         = 'Registration validation failed, please try again!';
    var $error_wikiname                     = '<!-- see setup method -->';
    var $error_username_exists              = 'Sorry, this user name already exists.';
    var $error_reserved_pagename            = '<!-- see setup method -->';
    var $error_pass1_too_short              = 'Password must contain at least %s characters.';
    var $error_pass2_empty                  = '<!-- see setup method -->';
    var $error_password_match               = 'Your passwords do not match.';
    var $error_password_login_match         = 'Please choose a safer password.';
    var $error_empty_password_or_hash       = 'Please fill your password or hash.';
    var $error_wrong_hash                   = 'Sorry, you entered a wrong password reminder.';
    var $error_empty_new_password           = 'You must also fill in a new password.';
    var $error_empty_new_pw_confirmation    = '<!-- see setup method -->';

    # UI
    var $ui_email_label                     = 'Your Email Address:';
    var $ui_doubleclick_label               = 'Doubleclick Editing:';
    var $ui_show_comments_label             = 'Show Comments by Default:';
    var $ui_page_revision_limit_label       = 'Page Revisions List Limit:';
    var $ui_recentchange_limit_label        = 'Recent Changes Display Limit:';
    var $ui_theme_label                     = 'Theme:';
    var $ui_wikiname_label                  = '<!-- see setup method -->';
    var $ui_password_label                  = 'Password (%s+ chars):';
    var $ui_login_redirect_label            = 'Redirect to %s after login';
    var $ui_pass2_label                     = 'Confirm password:';
    var $ui_temppw_label                    = 'Password reminder:';
    var $ui_current_pw_label                = 'Your current password:';
    var $ui_pw_reminder_label               = 'Password reminder:';
    var $ui_new_password_label              = 'Your new password:';
    var $ui_new_password_confirm_label      = 'Confirm new password:';
    var $ui_new_user_label                  = '';

    var $ui_heading_login                   = '===Login===';
    var $ui_heading_register                = '===Login/Register===';
    var $ui_heading_pwreminder              = '===Forgot your password?===';
    var $ui_heading_pwchange                = 'Change your password';
    var $ui_heading_quick_links             = 'Quick links';
    var $ui_login_subheader                 = "If you're already a registered user, log in here!";
    var $ui_new_user_subheader              = '<!-- see setup method -->';
    var $ui_retrieve_pw_subheader           = '<!-- see setup method -->';

    var $button_update_settings             = 'Update Settings';
    var $button_logout                      = 'Logout';
    var $button_login                       = 'Login';
    var $button_register                    = 'Register';
    var $button_recaptcha                   = 'Submit ReCAPTCHA';
    var $button_pwchange                    = 'Change Password';

    var $check_it                           = 'checked="checked"';
    var $select_it                          = 'selected="selected"';

    # class settings
    var $class_input_error                  = 'highlight error';
    var $class_email                        = '';
    var $class_revisioncount                = '';
    var $class_changescount                 = '';
    var $class_pwreminder                   = '';
    var $class_pwreminder_name              = '';
    var $class_oldpass                      = '';
    var $class_new_password                 = '';
    var $class_new_password_confirm         = '';

    # template blocks
    var $user_settings_form                 = '';
    var $pw_update_form                     = '';
    var $quick_links_block                  = '';
    var $login_form                         = '';
    var $registration_form                  = '';
    var $pw_reminder_form                   = '';

    # requests
    var $is_logout_request                  = FALSE;
    var $is_update_request                  = FALSE;
    var $is_pwchange_request                = FALSE;
    var $is_login_request                   = FALSE;
    var $is_registration_stage1             = FALSE;
    var $is_registration_stage2             = FALSE;
    var $is_pwreminder_request              = FALSE;

    # internal
    var $UserAuth                           = array();
    var $FormErrors                         = array();
    var $retrieve_pw_error                  = '';
    var $FormValues                         = array();
    var $UrlParams                          = array();
    var $FeedbackList                       = array();
    var $RecaptchaError                     = NULL;
    var $show_recaptcha                     = FALSE;
    var $pw_selected                        = '';
    var $hash_selected                      = '';
    var $pwchange_error                     = FALSE;


    function action_set_up()
    {
        $this->UserAuth = new URAuth($this->Wikka);
        $this->save_referrer();

        # set action
        if ( isset($_POST['action']) ) {
            $this->action = $_POST['action'];
        }
        $_post_submit = ( isset($_POST['submit']) ) ? $_POST['submit'] : NULL;
        $_post_logout = ( isset($_POST['logout']) ) ? $_POST['logout'] : NULL;

        # request tree
        $this->is_logout_request = ($_post_logout == $this->button_logout);

        $this->is_login_request = ($this->action == 'login') &&
            ($_post_submit == $this->button_login);

        $this->is_registration_stage1 = ($_post_submit == $this->button_register) &&
            $this->get_config('allow_user_registration');

        $this->is_registration_stage2 = isset($_POST['recaptcha_submit']) &&
            ($_POST['recaptcha_submit'] == $this->button_recaptcha) &&
            $this->get_config('allow_user_registration');

        $this->is_pwreminder_request = ($this->action == 'updatepass');

        $this->is_update_request = ($this->action == 'update');

        $this->is_pwchange_request = ($this->action == 'changepass');

        # long ui and error settings
        $this->quick_links = <<<XHTML
See a list of pages you own (MyPages) and pages you've edited (MyChanges).
XHTML;
        $this->ui_wikiname_label = <<<XHTML
Your <abbr title="A WikiName is formed by two or more capitalized words
without space, e.g. JohnDoe">WikiName</abbr>:
XHTML;
        $this->ui_new_user_subheader = <<<XHTML
Not a registered user?  Fill in these fields to sign up now and login now!
XHTML;
        $this->error_user_suspended = <<<XHTML
Sorry, this account has been suspended. Please contact an administrator for further details.
XHTML;
        $this->error_wikiname = <<<XHTML
Username must be formatted as a ##""WikiName""##, e.g. ##""JohnDoe""##.
XHTML;
        $this->error_reserved_pagename = <<<XHTML
Sorry, this name is reserved for a page. Please choose a different name.
XHTML;
        $this->ui_retrieve_pw_subheader = <<<XHTML
If you need a password reminder, click [[PasswordForgotten here]].
You can login here using your password reminder.
XHTML;
        $this->error_pass2_empty = <<<XHTML
Please confirm your password in order to update your account.
XHTML;
        $this->error_empty_new_pw_confirmation = <<<XHTML
Please confirm your new password in order to update your account.
XHTML;
    }

    function main()
    {
        $this->action_set_up();

        # logout request
        if ( $this->is_logout_request )
        {
            return $this->process_logout_request();
        }

        # user logged in
        elseif ( $this->is_logged_in )
        {
            $this->load_user_settings();

            if ( $this->is_update_request ) {
                $this->validate_datasource();
                if ( $this->is_valid_update_request() ) {
                    $this->update_user_settings();
                }
            }

            if ( $this->is_pwchange_request ) {
                $this->process_pwchange_request();
            }

            if ( $this->FormErrors ) {
                $this->add_feedback($this->FormErrors, 'error');
            }
            $this->_set_user_settings_form();
            $this->_set_pwchange_request_form();
            $this->_set_quick_links_block();
        }

        # not logged in
        else {
            # login request
            if ( $this->is_login_request ) {
                $this->process_login_request();
            }

            # registration request
            elseif ( $this->is_registration_stage1 ) {
                $this->process_registration_stage1();
            }
            elseif ( $this->is_registration_stage2 ) {
                $this->process_registration_stage2();
            }

            # password reminder request
            if ( $this->is_pwreminder_request ) {
                $this->process_pwreminder_request();
            }

            if ( $this->FormErrors ) {
                $this->add_feedback($this->FormErrors, 'error');
            }
            $this->_set_login_registration_stage();
            $this->_set_pw_reminder_form();
        }

        return $this->_build_page();
    }

    function output($content) {
        print $content;
    }


    function process_logout_request() {
        $this->UrlParams[] = 'out=true';
        $this->Wikka->LogoutUser();
	$this->refresh_page();
    }

    function process_login_request()
    {
        # validate
        if ( ! $this-> is_valid_login_request() ) {
            return FALSE;
        }

        # get user name
        if ( ! $LoginUser = $this->Wikka->LoadUser($this->Post['name']) ) {
            $this->FormErrors[] = $this->error_user_not_found;
            $this->class_login = $this->class_input_error;
            return FALSE;
        }

        # check status and password
        $SuspendedStatus = array('suspended', 'deleted', 'banned');
        switch( TRUE ) {
            case ( in_array($LoginUser['status'], $SuspendedStatus) ):
                $this->FormErrors[] = $this->error_user_suspended;
                $this->class_login = $this->class_input_error;
                break;
            case ( md5($_POST['password']) != $LoginUser['password'] ):
                $this->FormErrors[] = $this->error_wrong_password;
                $this->class_pass1 = $this->class_input_error;
                break;
            default:
                $this->log_user_in($LoginUser['name']);
        }
    }

    function is_valid_login_request()
    {
        $Form = array();
        $Form['login'] = isset($_POST['name']) ? trim($_POST['name']) : '';
        $Form['pass1'] = isset($_POST['password']) ? trim($_POST['password']) : '';

        # validate form values
        if ( strlen($Form['login']) == 0 ) {
            $this->FormErrors[] = $this->error_username_empty;
            $this->class_login = $this->class_input_error;
        }

        if ( strlen($Form['pass1']) == 0 ) {
            $this->FormErrors[] = $this->error_pass1_empty;
            $this->class_pass1 = $this->class_input_error;
        }

        $this->FormValues = $Form;
        return count($this->FormErrors) == 0;
    }

    function log_user_in($user_name, $url_params=FALSE)
    {
        $this->Wikka->SetUser($this->Wikka->LoadUser($user_name));

        # set session redirect
        if ( isset($_POST['do_redirect_post']) ) {
            $_SESSION['do_redirect'] = isset($_POST['do_redirect']) ? 1 : 0;
        }

        $do_redirect = isset($_SESSION['do_redirect']) ? $_SESSION['do_redirect'] : FALSE;
        $go_back = isset($_SESSION['go_back']) ? $_SESSION['go_back'] : FALSE;
        if ( $do_redirect && $go_back )
        {
            unset($_SESSION['do_redirect']);
            unset($_SESSION['go_back']);
            unset($_SESSION['go_back_tag']);
            $this->Wikka->Redirect($go_back);
        }
        else
        {
            if ( $url_params ) {
                $this->UrlParams[] = $url_params;
            }
            $this->refresh_page();
        }
    }

    function process_registration_stage1()
    {
        if ( $this->is_valid_registration() ) {
            $_SESSION['Registration'] = $this->FormValues;
            $this->show_recaptcha = TRUE;
        }
    }

    function process_registration_stage2()
    {
        if ( $this->is_valid_recaptcha() ) {
            $user_name = $this->insert_new_user();
            $this->insert_new_user_page($user_name);
            $this->log_user_in($user_name, 'registered=true');
        }
        else {
            $this->FormErrors[] = 'Your recaptcha did not validate. Please try again.';
            $this->show_recaptcha = TRUE;
        }
    }

    function insert_new_user()
    {
        $sqlf = <<<HERESQL
INSERT INTO %s
SET
    name = '%s',
    email = '%s',
    password = MD5('%s'),
    signuptime = NOW()
HERESQL;

        $ParamList = array(
            $this->get_config('table_prefix') . 'users',
            $_SESSION['Registration']['login'],
            $_SESSION['Registration']['email'],
            $_SESSION['Registration']['pass1']
        );
        $user_name = $_SESSION['Registration']['login'];
        unset($_SESSION['Registration']);

        # insert new user
        $sql = $this->safe_sql($sqlf, $ParamList);
        $this->Wikka->Query($sql);
        return $user_name;
    }

    function insert_new_user_page($user_name)
    {
        $body_f = <<<HERESQL
=====%s=====
Welcome to **%s**
Feel free to update this page.

----
==registered on %s==
HERESQL;

        $body = sprintf( $body_f,
                         $user_name,
                         $this->get_config('wakka_name'),
                         date('j F Y') );
        $note = 'auto-created when user registered';
        $this->create_page($user_name, $body, $note, $user_name);
        $this->Wikka->SaveACL($user_name, 'write', $this->Wikka->TrimACLs($user_name));
        $this->Wikka->SaveACL($user_name, 'read', $this->Wikka->TrimACLs('*'));
        $this->Wikka->SaveACL($user_name, 'comment', $this->Wikka->TrimACLs('*'));
    }

    function is_valid_registration()
    {
        $Form = array();
        $Form['login'] = trim($_POST['name']);
        $Form['email'] = trim($this->Wikka->GetSafeVar('email', 'post'));
        $Form['pass1'] = $_POST['password'];
        $Form['pass2'] = $_POST['confpassword'];

        # validate form values
        $this->FormErrors = array();
        if ( $this->UserAuth->URAuthVerify() === FALSE ) {
            $this->FormErrors[] = $this->error_invalid_registration;
        }

        if ( strlen($Form['login']) == 0 ) {
            $this->FormErrors[] = $this->error_username_empty;
            $this->class_login = $this->class_input_error;
        }
        elseif ( $existingUser = $this->Wikka->LoadUser($_POST['name']) ) {
            $this->FormErrors[] = $this->error_username_exists;
            $this->class_login = $this->class_input_error;
        }
        elseif ( ! $this->Wikka->IsWikiName($Form['login']) ) {
            $this->FormErrors[] = $this->error_wikiname;
            $this->class_login = $this->class_input_error;
        }
        elseif ( $this->Wikka->existsPage($Form['login'],NULL,NULL,FALSE) ) {
            $this->FormErrors[] = $this->error_reserved_pagename;
            $this->class_login = $this->class_input_error;
        }

        if ( strlen($Form['pass1']) == 0 ) {
            $this->FormErrors[] = $this->error_pass1_empty;
            $this->class_pass1 = $this->class_input_error;
        }
        elseif ( strlen($Form['pass1']) < $this->password_min_length ) {
            $this->FormErrors[] = sprintf($this->error_pass1_too_short,
                                          $this->password_min_length);
            $this->class_pass1 = $this->class_input_error;
        }
        elseif ( strlen($Form['pass2']) == 0 ) {
            $this->FormErrors[] = $this->error_pass2_empty;
            $this->class_pass2 = $this->class_input_error;
        }
        elseif ( $Form['pass1'] != $Form['pass2'] ) {
            $this->FormErrors[] = $this->error_password_match;
            $this->class_pass1 = $this->class_input_error;
            $this->class_pass2 = $this->class_input_error;
        }
        elseif ( $Form['pass1'] == $Form['login'] ) {
            $this->FormErrors[] = $this->error_password_login_match;
            $this->class_pass1 = $this->class_input_error;
            $this->class_pass2 = $this->class_input_error;
        }

        if ( strlen($Form['email']) == 0 ) {
            $this->FormErrors[] = $this->error_email_address_required;
            $this->class_email = $this->class_input_error;
        }
        elseif ( !preg_match($this->valid_email_pattern, $Form['email']) ) {
            $this->FormErrors[] = $this->error_invalid_email_address;
            $this->class_email = $this->class_input_error;
        }

        $this->FormValues = $Form;
        return count($this->FormErrors) == 0;
    }

    function is_valid_update_request() {

        $Form = array();
        $Form['email']           = $this->Wikka->GetSafeVar('email', 'post');
        $Form['doubleclickedit'] = $this->Wikka->GetSafeVar('doubleclickedit', 'post');
        $Form['show_comments']   = $this->Wikka->GetSafeVar('show_comments', 'post');
        $Form['revisioncount']   = $this->Wikka->GetSafeVar('revisioncount', 'post');
        $Form['changescount']    = $this->Wikka->GetSafeVar('changescount', 'post');
        $Form['theme']           = $this->Wikka->GetSafeVar('theme', 'post');

        // validate form
        $this->FormErrors = array();
        if ( strlen($Form['email']) == 0 ) {
            $this->FormErrors[] = $this->error_email_address_required;
            $this->class_email = $this->class_input_error;
        }
        elseif ( !preg_match($this->valid_email_pattern, $Form['email']) ) {
            $this->FormErrors[] = $this->error_invalid_email_address;
            $this->class_email = $this->class_input_error;
        }

        if ( ($Form['revisioncount'] < $this->revision_limit_min) ||
             ($Form['revisioncount'] > $this->revision_limit_max) ) {
            $this->FormErrors[] = sprintf($this->error_invalid_revision_limit,
                                          $this->revision_limit_min,
                                          $this->revision_limit_max);
            $this->class_revisioncount = $this->class_input_error;
        }

        if ( ($Form['changescount'] < $this->recentchanges_limit_min) ||
             ($Form['changescount'] > $this->recentchanges_limit_max) ) {
            $this->FormErrors[] = sprintf($this->error_invalid_change_limit,
                                          $this->recentchanges_limit_min,
                                          $this->recentchanges_limit_max);
            $this->class_changescount = $this->class_input_error;
        }

        $this->FormValues = $Form;
        return count($this->FormErrors) == 0;
    }

    function is_valid_recaptcha() {
        require_once('3rdparty/plugins/recaptcha/recaptchalib.php');

        $RecaptchaResponse = recaptcha_check_answer(
            $this->Wikka->GetConfigValue('rc_private_key'),
            $_SERVER['REMOTE_ADDR'],
            $_POST["recaptcha_challenge_field"],
            $_POST["recaptcha_response_field"]
        );

        if ( ! $RecaptchaResponse->is_valid ) {
            $this->RecaptchaError = $RecaptchaResponse->error;
            #$this->FormErrors[] = $this->RecaptchaError;
        }

        return $RecaptchaResponse->is_valid;
    }

    function process_pwchange_request()
    {
        $oldpass = $_POST['oldpass'];
        $password = trim($_POST['password']);
        $password_confirm = trim($_POST['password_confirm']);
        $update_option = $this->Wikka->GetSafeVar('update_option', 'post');

        switch( TRUE ) {
            case ( strlen($oldpass) == 0 ):
                $this->pwchange_error = $this->error_empty_password_or_hash;
                $this->class_oldpass = $this->class_input_error;
                break;
            case ( ($update_option == 'pw') && md5($oldpass) != $this->user['password'] ):
                $this->pwchange_error = $this->error_wrong_password;
                $this->pw_selected = $this->select_it;
                $this->class_oldpass = $this->class_input_error;
                break;
            case ( ($update_option == 'hash') && $oldpass != $this->user['password'] ):
                $this->pwchange_error = $this->error_wrong_hash;
                $this->hash_selected = $this->select_it;
                $this->class_oldpass = $this->class_input_error;
                break;
            case ( strlen($password) == 0 ):
                $this->pwchange_error = $this->error_empty_new_password;
                $this->class_oldpass = $this->class_input_error;
                $this->class_new_password = $this->class_input_error;
                break;
            case ( strlen($password) < $this->password_min_length ):
                $this->pwchange_error = sprintf($this->error_pass1_too_short,
                                                $this->password_min_length);
                $this->class_oldpass = $this->class_input_error;
                $this->class_new_password = $this->class_input_error;
                break;
            case ( strlen($password_confirm) == 0 ):
                $this->pwchange_error = $this->error_empty_new_pw_confirmation;
                $this->class_oldpass = $this->class_input_error;
                $this->class_new_password = $this->class_input_error;
                $this->class_new_password_confirmation = $this->class_input_error;
                break;
            case ( $password_confirm != $password ):
                $this->pwchange_error = $this->error_password_match;
                $this->class_oldpass = $this->class_input_error;
                $this->class_new_password = $this->class_input_error;
                $this->class_new_password_confirmation = $this->class_input_error;
                break;
            default:
                $this->update_user_password($this->user['name'], $password);
		$this->user['password'] = md5($password);
                $this->UrlParams[] = 'newpassword=true';
                $this->refresh_page();
        }
    }

    function process_pwreminder_request()
    {
        $name = trim($this->Wikka->GetSafeVar('yourname', 'post'));

        if ( strlen($name) == 0 ) {
            $this->retrieve_pw_error = $this->error_username_empty;
            $this->class_pwreminder_name = $this->class_input_error;
        }
        elseif ( ! $this->Wikka->IsWikiName($name) ) {
            $this->retrieve_pw_error = $this->error_wikiname;
            $this->class_pwreminder_name = $this->class_input_error;
        }
        elseif ( ! $this->Wikka->LoadUser($name) ) {
            $this->retrieve_pw_error = $this->error_user_not_found;
            $this->class_pwreminder_name = $this->class_input_error;
        }
        elseif ( $LoadedUser = $this->Wikka->LoadUser($name) ) {
            if ( $LoadedUser['password'] == trim($_POST['temppassword']) ) {
                $this->log_user_in($name);
            }
            else {
                $this->retrieve_pw_error = $this->error_wrong_password;
                $this->class_pwreminder_pass = $this->class_input_error;
            }
        }
    }

    function validate_datasource()
    {
        $keep_post_data = FALSE;

        # check if page key was stored in session
        if ( isset($_POST['form_id'] )
            && ($aKey = $this->Wikka->getSessionKey($_POST['form_id'])) !== FALSE ) {
            # check if correct name,key pair was passed
            if ( ($rc = $this->Wikka->hasValidSessionKey($aKey)) == TRUE ) {
                $keep_post_data  = TRUE;
            }
        }

        if( ! $keep_post_data ) {
            unset($_POST);
            $this->add_feedback('there is a problem with your session', 'error');
        }
    }

    function save_referrer() {
        $regex_referrer = sprintf('@^%s([^\/\?&]*)@i',
                                  preg_quote($this->get_config('base_url'), '@'));
        if ( isset($_SERVER['HTTP_REFERER']) &&
            preg_match($regex_referrer, $_SERVER['HTTP_REFERER'], $match)) {
            if (strcasecmp($this->Wikka->tag, $match[1]))
            {
                $_SESSION['go_back'] = $_SERVER['HTTP_REFERER'];

                # save the tag of referring page so it can be shown in label
                # <Go back to ...>.  Must use a session here in case user
                # refreshes the page.
                $_SESSION['go_back_tag'] = $match[1];
            }
        }
    }

    function load_user_settings() {
        /*
            $this->user set _load_wikka_acl method in base action class.  This
            includes all database data.
        */
        $this->user['usertheme'] = ( ! empty($this->user['theme']) )
            ? $this->user['theme']
            : $this->Wikka->GetConfigValue('theme');
    }

    function update_user_settings()
    {
        $sqlf = <<<HERESQL
UPDATE %s
SET
    email = '%s',
    doubleclickedit = '%s',
    show_comments = '%s',
    revisioncount = '%s',
    changescount = '%s',
    theme = '%s'
WHERE
    name = '%s'
LIMIT 1
HERESQL;

        $ParamList = array(
            $this->get_config('table_prefix') . 'users',
            $this->FormValues['email'],
            $this->FormValues['doubleclickedit'],
            $this->FormValues['show_comments'],
            $this->FormValues['revisioncount'],
            $this->FormValues['changescount'],
            $this->FormValues['theme'],
            $this->user['name'],
        );

        $sql = $this->safe_sql($sqlf, $ParamList);
        $this->Wikka->Query($sql);
        $this->Wikka->SetUser($this->Wikka->LoadUser($this->user['name']));

        $this->UrlParams[] = 'stored=true';
        $this->refresh_page();
    }

    function update_user_password($name, $password)
    {
        $sqlf = <<<HERESQL
UPDATE %s
SET
    password = md5('%s')
WHERE
    name = '%s'
HERESQL;

        $ParamList = array(
            $this->get_config('table_prefix') . 'users',
            $password,
            $name
        );

        $sql = $this->safe_sql($sqlf, $ParamList);
        $this->Wikka->Query($sql);
        $this->Wikka->SetUser($this->Wikka->LoadUser($name));
    }

    function refresh_page()
    {
        $query_head = '';
        if ( $this->UrlParams ) {
            $query_head = ($this->get_config('rewrite_mode') == 1) ? '?' : '&';
        }

        $redirect_url = sprintf( '%s%s%s',
                                 $this->here,
                                 $query_head,
                                 implode('&', $this->UrlParams) );
        $this->Wikka->Redirect($redirect_url);
        exit();
    }


    /**
     * Templating Methods
     */
    function add_feedback($Mixed, $class='default') {
        if ( is_array($Mixed) ) {
            foreach ( $Mixed as $message ) {
                $this->FeedbackList[] = sprintf('<div class="feedback %s">%s</div>',
                                                 $class, $message);
            }
        }
        else {
            $this->FeedbackList[] = sprintf('<div class="feedback %s">%s</div>',
                                            $class, $message);
        }
    }

    function _set_user_settings_form() {
        $htmlf = <<<XHTML
<h3>User settings</h3>

<!-- Open Form -->%s

    <table class="usersettings">
    <tr>
        <td>&nbsp;</td>
        <td>Hello, %s!</td>
    </tr>

    <!-- confirmation message -->%s

    <tr>
        <td align="right">{$this->ui_email_label}</td>
        <td><input class="{$this->class_email}" name="email" value="%s" size="40" /></td>
    </tr>

    <tr>
        <td align="right">{$this->ui_doubleclick_label}</td>
        <td>
            <input type="hidden" name="doubleclickedit" value="N" />
            <input type="checkbox" name="doubleclickedit" value="Y" %s />
        </td>
    </tr>

    <tr>
        <td align="right">{$this->ui_show_comments_label}</td>
        <td>
            <input type="hidden" name="show_comments" value="N" />
            <input type="checkbox" name="show_comments" value="Y" %s />
        </td>
    </tr>

    <tr>
        <td align="right">{$this->ui_page_revision_limit_label}</td>
        <td>
            <input class="{$this->class_revisioncount}" name="revisioncount" value="%s" size="2" />
        </td>
    </tr>

    <tr>
        <td align="right">{$this->ui_recentchange_limit_label}</td>
        <td>
            <input class="{$this->class_changescount}" name="changescount" value="%s" size="2" />
        </td>
    </tr>

    <tr>
        <td align="right">{$this->ui_theme_label}</td>
        <td>%s</td>
    </tr>

    <tr>
        <td>&nbsp;</td>
        <td>
            <input type="hidden" name="action" value="update" />
            <input type="submit" value="{$this->button_update_settings}" />
            <!-- old logout button code removed -->
            <input id="logout" name="logout" type="submit" value="{$this->button_logout}" />
        </td>
    </tr>
    </table>

<!-- Close Form --> %s
XHTML;

        $message = '';
        switch ( TRUE ) {
            case ( isset($_GET['out']) && $_GET['out'] == 'true' ):
                $message = $this->message_logout;
                break;
            case ( isset($_GET['registered']) && $_GET['registered'] == 'true' ):
                $message = $this->message_registered;
                break;
            case ( isset($_GET['stored']) && $_GET['stored'] == 'true' ):
                $message = $this->message_user_updated;
                break;
            case ( isset($_GET['newpassword']) && $_GET['newpassword'] == 'true' ):
                $message = $this->message_password_changed;
        }

        $message_tr = '';
        if ( $message ) {
            $message_tr_f = <<<XHTML
    <tr>
        <td>&nbsp;</td>
        <td><em class="success">%s</em></td>
    </tr>
XHTML;
            $message_tr = sprintf($message_tr_f,
                                  $this->Wikka->Format($message));
        }

        $this->user_settings_form = sprintf( $htmlf,
            $this->Wikka->FormOpen(),
            $this->Wikka->Link($this->user['name']),
            $message_tr,
            $this->Wikka->htmlspecialchars_ent($this->user['email']),
            $this->user['doubleclickedit'] == 'Y' ? 'checked="checked"' : '',
            $this->user['show_comments'] == 'Y' ? 'checked="checked"' : '',
            $this->Wikka->htmlspecialchars_ent($this->user['revisioncount']),
            $this->Wikka->htmlspecialchars_ent($this->user['changescount']),
            $this->_get_theme_box(),
            $this->Wikka->FormClose() );
    }

    function _set_pwchange_request_form()
    {
        $htmlf = <<<XHTML
    <hr />

<!-- Open Form -->%s

    <input type="hidden" name="action" value="changepass" />
    <h5>{$this->ui_heading_pwchange}</h5>

    <table class="usersettings">

        <!-- pwchange error row -->%s

        <tr>
            <td align="right">
                <select name="update_option">
                    <option value="pw" {$this->pw_selected}>
                        {$this->ui_current_pw_label}
                    </option>
                    <option value="hash" {$this->hash_selected}>
                        {$this->ui_pw_reminder_label}
                    </option>
                </select>
            </td>
            <td>
                <input class="{$this->class_oldpass}" type="password"
                       name="oldpass" size="40" />
            </td>
        </tr>
        <tr>
            <td align="right">{$this->ui_new_password_label}</td>
            <td>
                <input class="{$this->class_new_password}" type="password"
                       name="password" size="40" />
            </td>
        </tr>
        <tr>
            <td align="right">{$this->ui_new_password_confirm_label}</td>
            <td>
                <input class="{$this->class_new_password_confirm}" type="password"
                       name="password_confirm" size="40" />
            </td>
        </tr>
        <tr>
            <td>&nbsp;</td>
            <td><input type="submit" value="{$this->button_pwchange}" size="40" /></td>
        </tr>
    </table>

<!-- Close Form -->%s

XHTML;

        $pwchange_error_tr = '';
        if ( $this->pwchange_error ) {
                $pwchange_error_tr_f = <<<XHTML
    <tr>
        <td>&nbsp;</td>
        <td><em class="error">%s</em></td>
    </tr>
XHTML;
            $pwchange_error_tr = sprintf($pwchange_error_tr_f,
                                         $this->Wikka->Format($this->pwchange_error));
        }


        $this->pw_update_form = sprintf( $htmlf,
            $this->Wikka->FormOpen(),
            $pwchange_error_tr,
            $this->Wikka->FormClose()
        );
    }

    function _set_quick_links_block() {
        $htmlf = <<<XHTML
    <hr />
    <h5>{$this->ui_heading_quick_links}</h5>
    %s
XHTML;

        $this->quick_links_block = sprintf(
            $htmlf,
            $this->Wikka->Format($this->quick_links)
        );
    }

    function _set_login_registration_stage() {
        if ( $this->show_recaptcha ) {
            $this->_set_registration_recaptcha();
        }
        else {
            $this->_set_login_registration_form();
        }
    }

    function _set_login_registration_form() {
        $htmlf = <<<XHTML
<!-- Open Form -->%s

    <input type="hidden" name="action" value="login" />

    <table class="usersettings">
    <tr>
        <td colspan="2">%s</td>
    </tr>

    <!-- message row -->%s

    <tr>
        <td>&nbsp;</td>
        <td>%s</td>
    </tr>
    <tr>
        <td align="right">{$this->ui_wikiname_label}</td>
        <td><input class="{$this->class_login}" name="name" size="40" value="%s" /></td>
    </tr>
    <tr>
        <td align="right">%s</td>
        <td><input class="{$this->class_pass1}" type="password" name="password" size="40" /></td>
    </tr>

    <!-- Go Back Row -->
    %s

    <tr>
        <td>&nbsp;</td>
        <td><input name="submit" type="submit" value="{$this->button_login}" size="40" /></td>
    </tr>

    <!-- Registration Form -->
    %s

    </table>

<!-- Close Form -->%s

XHTML;

        # message row
        $message = '';
        switch ( TRUE ) {
            case ( isset($_GET['out']) && $_GET['out'] == 'true' ):
                $message = $this->message_logout;
                break;
        }

        $message_tr = '';
        if ( $message ) {
            $message_tr_f = <<<XHTML
    <tr>
        <td>&nbsp;</td>
        <td><em class="success">%s</em></td>
    </tr>
XHTML;
            $message_tr = sprintf($message_tr_f,
                                  $this->Wikka->Format($message));
        }

        # go back row
        $go_back_tr = '';
        if ( isset($_SESSION['go_back']) ) {
            $go_back_tr_f = <<<XHTML
    <tr>
        <td align="right">%s</td>
        <td>
            <input type='checkbox' name='do_redirect' id='do_redirect' %s />
            <input type='hidden' name='do_redirect_post' value='1' />
        </td>
    </tr>
XHTML;

            $go_back_tr = sprintf( $go_back_tr_f,
                sprintf($this->ui_login_redirect_label, $_SESSION['go_back_tag']),
                (isset($_POST['do_redirect']) || empty($_POST)) ? $this->check_it : ''
            );
        }

        # heading
        if ( $this->get_config('allow_user_registration') ) {
            $heading = $this->Wikka->Format($this->ui_heading_register);
        }
        else {
            $heading = $this->Wikka->Format($this->ui_heading_login);
        }

        # user name
        $username = '';
        if ( isset($this->FormValues['login']) ) {
            $username = $this->FormValues['login'];
        }
        elseif ( isset($_SESSION['wikka_login']) ) {
            $username = $_SESSION['wikka_login'];
            unset($_SESSION['wikka_login']);
        }

        $this->registration_form = sprintf( $htmlf,
            $this->Wikka->FormOpen(),
            $heading,
            $message_tr,
            $this->Wikka->Format($this->ui_login_subheader),
            $username,
            sprintf($this->ui_password_label, $this->password_min_length),
            $go_back_tr,
            $this->_set_registration_block(),
            $this->Wikka->FormClose()
        );
    }

    function _set_registration_block()
    {
        if ( ! $this->get_config('allow_user_registration') ) {
            return '<!-- registration disabled -->';
        }

        $registration_form_f = <<<XHTML
    <tr><td><!-- spacer --></td><td>&nbsp;</td></tr>

    <tr>
        <td>&nbsp;</td>
        <td width="500">%s</td>
    </tr>

    <tr>
        <td colspan="2" align="left">%s</td>
    </tr>

    <tr>
        <td align="right">{$this->ui_pass2_label}</td>
        <td><input class="{$this->class_pass2}" type="password" name="confpassword" size="40" /></td>
    </tr>

    <tr>
        <td align="right">{$this->ui_email_label}</td>
        <td><input class="{$this->class_email}" name="email" size="40" value="%s" /></td>
    </tr>

    <tr>
        <td>&nbsp;</td>
        <td><input name="submit" type="submit" value="{$this->button_register}" size="40" /></td>
    </tr>
XHTML;
        $user_email = '';
        if ( isset($this->FormValues['email']) ) {
            $user_email = $this->FormValues['email'];
        }
        elseif ( isset($_SESSION['wikka_email']) ) {
            $user_email = $_SESSION['wikka_email'];
            unset($_SESSION['wikka_email']);
        }

        return sprintf($registration_form_f,
            $this->Wikka->Format($this->ui_new_user_subheader),
            $this->_get_auth_display(),
            $user_email
        );
    }

    function _set_registration_recaptcha() {
        require_once('3rdparty/plugins/recaptcha/recaptchalib.php');

        $htmlf = <<<XHTML
<h5>To deter bots and spammers, please complete this ReCAPTCHA challenge</h5>
<div class="recaptcha">
    %s
    %s
    <input name="recaptcha_submit" type="submit" value="{$this->button_recaptcha}" />
    %s
</div>
XHTML;
        $this->registration_form = sprintf( $htmlf,
            $this->Wikka->FormOpen(),
            recaptcha_get_html(
                $this->Wikka->GetConfigValue('rc_public_key'),
                $this->RecaptchaError ),
            $this->Wikka->FormClose
        );
    }

    function _set_pw_reminder_form() {
        $htmlf = <<<XHTML
    <br />
    <hr />

<!-- Open Form -->%s

    <input type="hidden" name="action" value="updatepass" />

    <table class="usersettings">
    <tr>
        <td colspan="2">%s</td>
        <td>&nbsp;</td>
    </tr>
    <tr>
        <td>&nbsp;</td>
        <td>%s</td>
    </tr>

    <!-- new error row -->%s

    <tr>
        <td align="right">{$this->ui_wikiname_label}</td>
        <td>
            <input class="{$this->class_pwreminder_name}" name="yourname" size="40" value="%s" />
        </td>
    </tr>
    <tr>
        <td align="right">{$this->ui_temppw_label}</td>
        <td>
            <input class="{$this->class_pwreminder_pass}" type="password"
                   name="temppassword" size="40" />
        </td>
    </tr>
    <tr>
        <td>&nbsp;</td>
        <td><input name="submit" type="submit" value="{$this->button_login}" size="40" /></td>
    </tr>
    </table>

<!-- Close Form -->%s
XHTML;

        $retrieve_pw_tr = '';
        if ( $this->retrieve_pw_error ) {
                $retrieve_pw_tr_f = <<<XHTML
    <tr>
        <td>&nbsp;</td>
        <td><em class="error">%s</em></td>
    </tr>
XHTML;
            $retrieve_pw_tr = sprintf($retrieve_pw_tr_f,
                                      $this->Wikka->Format($this->retrieve_pw_error));
        }

        $this->pw_reminder_form = sprintf( $htmlf,
            $this->Wikka->FormOpen(),
            $this->Wikka->Format($this->ui_heading_pwreminder),
            $this->Wikka->Format($this->ui_retrieve_pw_subheader),
            $retrieve_pw_tr,
            $this->Wikka->GetSafeVar('yourname', 'post'),
            $this->Wikka->FormClose()
        );
    }

    function _build_page()
    {
        $htmlf = <<<XHTML
<div id="recaptcha_login">
<!-- Feedback Messages -->
%s


<!-- *** User (Logged In) Block *** -->
<!-- User Settings Page -->
%s

<!-- Password Update Form -->
%s

<!-- Quick Links Block -->
%s


<!-- *** Visitor (Not Logged In) Block *** -->
<!-- Login Form -->
%s

<!-- Registration Form -->
%s

<!-- Temp Password Form -->
%s
</div>
XHTML;

        if ( ! $this->get_config('allow_user_registration') ) {
            $this->registration_form = '';
        }

        if ( $this->show_recaptcha ) {
            $this->pw_reminder_form = '';
        }

        return sprintf( $htmlf,
                        implode('', $this->FeedbackList),
                        $this->user_settings_form,
                        $this->pw_update_form,
                        $this->quick_links_block,
                        $this->login_form,
                        $this->registration_form,
                        $this->pw_reminder_form );
    }

    function _get_theme_box() {
        ob_start();
        $this->Wikka->SelectTheme($this->user['usertheme']);
        return ob_get_clean();
    }

    function _get_auth_display() {
        ob_start();
        $this->UserAuth->URAuthDisplay();
        return ob_get_clean();
    }

}

# Main Routine
try {
    $Action = new UserLoginAction($this, $vars);
    $content = $Action->main();
    $Action->output($content);
}
catch(Exception $e) {
    printf('<em class="error">%s</em>', $e->getMessage());
}
